/**
 *    Copyright 2009-2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ReflectPermission;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.apache.ibatis.reflection.invoker.GetFieldInvoker;
import org.apache.ibatis.reflection.invoker.Invoker;
import org.apache.ibatis.reflection.invoker.MethodInvoker;
import org.apache.ibatis.reflection.invoker.SetFieldInvoker;
import org.apache.ibatis.reflection.property.PropertyNamer;

/*
 * This class represents a cached set of class definition information that
 * allows for easy mapping between property names and getter/setter methods.
 */
/**
 * @author Clinton Begin
 */
/**
 * 反射器, 属性->getter/setter的映射器，而且加了缓存 可参考ReflectorTest来理解这个类的用处
 *
 */
public class Reflector {
	/**
	 * 是否开启类缓存
	 */
	private static boolean classCacheEnabled = true;
	private static final String[] EMPTY_STRING_ARRAY = new String[0];
	/**
	 * 这里用ConcurrentHashMap，多线程支持，作为一个缓存
	 */
	private static final Map<Class<?>, Reflector> REFLECTOR_MAP = new ConcurrentHashMap<Class<?>, Reflector>();

	private Class<?> type;
	/**
	 * 可读属性名 getter的属性列表
	 */
	private String[] readablePropertyNames = EMPTY_STRING_ARRAY;
	/**
	 * 可写属性名 setter的属性列表
	 */
	private String[] writeablePropertyNames = EMPTY_STRING_ARRAY;
	/**
	 * setter的方法列表
	 */
	private Map<String, Invoker> setMethods = new HashMap<String, Invoker>();
	/**
	 * getter的方法列表
	 */
	private Map<String, Invoker> getMethods = new HashMap<String, Invoker>();
	/**
	 * setter的类型列表
	 */
	private Map<String, Class<?>> setTypes = new HashMap<String, Class<?>>();
	/**
	 * getter的类型列表
	 */
	private Map<String, Class<?>> getTypes = new HashMap<String, Class<?>>();
	/**
	 * 构造函数
	 */
	private Constructor<?> defaultConstructor;
	/**
	 * 大小写不敏感属性Map
	 */
	private Map<String, String> caseInsensitivePropertyMap = new HashMap<String, String>();

	/**
	 * 初始化--反射器
	 * 
	 * @param clazz
	 */
	private Reflector(Class<?> clazz) {
		type = clazz;
		// 加入构造函数
		addDefaultConstructor(clazz);
		// 加入getter
		addGetMethods(clazz);
		// 加入setter
		addSetMethods(clazz);
		// 加入字段
		addFields(clazz);
		readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
		writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
		// 遍历 可读属性名 getter的属性列表
		for (String propName : readablePropertyNames) {
			// 这里为了能找到某一个属性，就把他变成大写作为map的key。。。
			caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
		}
		// 遍历 可写属性名 setter的属性列表
		for (String propName : writeablePropertyNames) {
			// 这里为了能找到某一个属性，就把他变成大写作为map的key。。。
			caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
		}
	}

	/**
	 * 添加一个默认的构造器
	 * 
	 * @param clazz
	 */
	private void addDefaultConstructor(Class<?> clazz) {
		// 获得制定参数类型的所有构造器
		Constructor<?>[] consts = clazz.getDeclaredConstructors();
		// 遍历
		for (Constructor<?> constructor : consts) {
			// 判断底层构造函数有没有参数,没有参数返回0
			if (constructor.getParameterTypes().length == 0) {
				// 判断是否可以访问私有方法
				if (canAccessPrivateMethods()) {
					try {
						// 为反射对象设置可访问标志，flag为true表明屏蔽Java语言的访问检查，使得对象的私有属性也可以被查询和设置
						constructor.setAccessible(true);
					} catch (Exception e) {
						// Ignored. This is only a final precaution, nothing we
						// can do.
					}
				}
				// 返回反射对象的可访问标志的值
				if (constructor.isAccessible()) {
					this.defaultConstructor = constructor;
				}
			}
		}
	}

	/**
	 * 添加get方法
	 * 
	 * @param cls
	 */
	private void addGetMethods(Class<?> cls) {
		Map<String, List<Method>> conflictingGetters = new HashMap<String, List<Method>>();
		// 这里getter和setter都调用了getClassMethods，有点浪费效率了。不妨把addGetMethods,addSetMethods合并成一个方法叫addMethods
		Method[] methods = getClassMethods(cls);
		// 遍历
		for (Method method : methods) {
			// 得到方法的名字
			String name = method.getName();
			// 判断是否以get开头并且名字的长度大于3
			if (name.startsWith("get") && name.length() > 3) {
				// 判断底层构造函数有没有参数,没有参数返回0
				if (method.getParameterTypes().length == 0) {
					// 方法转为属性
					name = PropertyNamer.methodToProperty(name);
					addMethodConflict(conflictingGetters, name, method);
				}
			} else if (name.startsWith("is") && name.length() > 2) {// 判断是否以is开头并且名字的长度大于2
				// 判断底层构造函数有没有参数,没有参数返回0
				if (method.getParameterTypes().length == 0) {
					// 方法转为属性
					name = PropertyNamer.methodToProperty(name);
					addMethodConflict(conflictingGetters, name, method);
				}
			}
		}
		// 解决方法冲突
		resolveGetterConflicts(conflictingGetters);
	}

	/**
	 * 解决get方法冲突
	 * 
	 * @param conflictingGetters
	 */
	private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
		// 遍历
		for (String propName : conflictingGetters.keySet()) {
			// 得到冲突的get方法
			List<Method> getters = conflictingGetters.get(propName);
			// 此处使用Iterator比使用for性能更好 ---迭代
			Iterator<Method> iterator = getters.iterator();
			// 下一个方法
			Method firstMethod = iterator.next();
			// 判断是否只有一个元素
			if (getters.size() == 1) {
				addGetMethod(propName, firstMethod);
			} else {
				Method getter = firstMethod;
				// 得到返回的类型
				Class<?> getterType = firstMethod.getReturnType();
				// 遍历
				while (iterator.hasNext()) {
					Method method = iterator.next();
					// 得到返回的类型
					Class<?> methodType = method.getReturnType();
					// 判断下个方法和当前方法返回类型是否一致
					if (methodType.equals(getterType)) {
						throw new ReflectionException(
								"Illegal overloaded getter method with ambiguous type for property " + propName
										+ " in class " + firstMethod.getDeclaringClass()
										+ ".  This breaks the JavaBeans "
										+ "specification and can cause unpredicatble results.");
					} else if (methodType.isAssignableFrom(getterType)) {// 判定Get方法返回类型所表示的类或接口与指定的
																			// Class
																			// 参数所表示的类或接口是否相同，或是否是其超类或超接口
						// OK getter type is descendant
					} else if (getterType.isAssignableFrom(methodType)) {// 判定方法类型所表示的类或接口与指定的
																			// Class
																			// 参数所表示的类或接口是否相同，或是否是其超类或超接口
						getter = method;
						getterType = methodType;
					} else {
						throw new ReflectionException(
								"Illegal overloaded getter method with ambiguous type for property " + propName
										+ " in class " + firstMethod.getDeclaringClass()
										+ ".  This breaks the JavaBeans "
										+ "specification and can cause unpredicatble results.");
					}
				}
				addGetMethod(propName, getter);
			}
		}
	}

	/**
	 * 得到get方法
	 * 
	 * @param name
	 * @param method
	 */
	private void addGetMethod(String name, Method method) {
		// 判断是否为有效的名称
		if (isValidPropertyName(name)) {
			getMethods.put(name, new MethodInvoker(method));
			getTypes.put(name, method.getReturnType());
		}
	}

	/**
	 * 添加set方法
	 * 
	 * @param cls
	 */
	private void addSetMethods(Class<?> cls) {
		Map<String, List<Method>> conflictingSetters = new HashMap<String, List<Method>>();
		Method[] methods = getClassMethods(cls);
		for (Method method : methods) {
			String name = method.getName();
			if (name.startsWith("set") && name.length() > 3) {
				if (method.getParameterTypes().length == 1) {
					name = PropertyNamer.methodToProperty(name);
					addMethodConflict(conflictingSetters, name, method);
				}
			}
		}
		resolveSetterConflicts(conflictingSetters);
	}

	/**
	 * 添加方法冲突
	 * 
	 * @param conflictingMethods
	 *            冲突的方法集
	 * @param name
	 * @param method
	 */
	private void addMethodConflict(Map<String, List<Method>> conflictingMethods, String name, Method method) {
		// 通过名字得到List
		List<Method> list = conflictingMethods.get(name);
		// 判断list是否为空
		if (list == null) {
			list = new ArrayList<Method>();
			// 添加新的方法集
			conflictingMethods.put(name, list);
		}
		list.add(method);
	}

	/**
	 * 解决set方法冲突
	 * 
	 * @param conflictingSetters
	 */
	private void resolveSetterConflicts(Map<String, List<Method>> conflictingSetters) {
		// 遍历
		for (String propName : conflictingSetters.keySet()) {
			// 得到冲突的set方法
			List<Method> setters = conflictingSetters.get(propName);
			// 得到第一个方法
			Method firstMethod = setters.get(0);
			// 判断是否只有一个元素
			if (setters.size() == 1) {
				addSetMethod(propName, firstMethod);
			} else {
				// 得到预期的类型
				Class<?> expectedType = getTypes.get(propName);
				// 判断是否为空
				if (expectedType == null) {
					throw new ReflectionException("Illegal overloaded setter method with ambiguous type for property "
							+ propName + " in class " + firstMethod.getDeclaringClass()
							+ ".  This breaks the JavaBeans " + "specification and can cause unpredicatble results.");
				} else {
					Iterator<Method> methods = setters.iterator();
					Method setter = null;
					// 遍历
					while (methods.hasNext()) {
						Method method = methods.next();
						// 判断方法参数的类型长度为1并且预期的类型和方法参数一致
						if (method.getParameterTypes().length == 1
								&& expectedType.equals(method.getParameterTypes()[0])) {
							setter = method;
							break;
						}
					}
					if (setter == null) {
						throw new ReflectionException(
								"Illegal overloaded setter method with ambiguous type for property " + propName
										+ " in class " + firstMethod.getDeclaringClass()
										+ ".  This breaks the JavaBeans "
										+ "specification and can cause unpredicatble results.");
					}
					addSetMethod(propName, setter);
				}
			}
		}
	}

	/**
	 * 添加set方法
	 * 
	 * @param name
	 * @param method
	 */
	private void addSetMethod(String name, Method method) {
		if (isValidPropertyName(name)) {
			setMethods.put(name, new MethodInvoker(method));
			setTypes.put(name, method.getParameterTypes()[0]);
		}
	}

	/**
	 * 添加 一个字段
	 * 
	 * @param clazz
	 */
	private void addFields(Class<?> clazz) {
		// 返回一个 Field 对象，该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
		Field[] fields = clazz.getDeclaredFields();
		// 遍历
		for (Field field : fields) {
			// 判断是否可以访问私人方法
			if (canAccessPrivateMethods()) {
				try {
					// 为反射对象设置可访问标志，flag为true表明屏蔽Java语言的访问检查，使得对象的私有属性也可以被查询和设置
					field.setAccessible(true);
				} catch (Exception e) {
					// Ignored. This is only a final precaution, nothing we can
					// do.
				}
			}
			if (field.isAccessible()) {
				// 判断setter的方法列表是否存在指定字段的名字
				if (!setMethods.containsKey(field.getName())) {
					// issue #379 - removed the check for final because JDK 1.5
					// allows
					// modification of final fields through reflection
					// (JSR-133). (JGB)
					// pr #16 - final static can only be set by the classloader
					// 以整数形式返回由此 Field 对象表示的字段的 Java 语言修饰符。
					int modifiers = field.getModifiers();
					if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {
						addSetField(field);
					}
				}
				if (!getMethods.containsKey(field.getName())) {
					addGetField(field);
				}
			}
		}
		if (clazz.getSuperclass() != null) {
			addFields(clazz.getSuperclass());
		}
	}

	/**
	 * 添加set字段
	 * 
	 * @param field
	 */
	private void addSetField(Field field) {
		// 是否为有效的名称
		if (isValidPropertyName(field.getName())) {
			setMethods.put(field.getName(), new SetFieldInvoker(field));
			setTypes.put(field.getName(), field.getType());
		}
	}

	/**
	 * 添加Get字段
	 * 
	 * @param field
	 */
	private void addGetField(Field field) {
		// 是否为有效的名称
		if (isValidPropertyName(field.getName())) {
			getMethods.put(field.getName(), new GetFieldInvoker(field));
			getTypes.put(field.getName(), field.getType());
		}
	}

	/**
	 * 是否为有效的名称
	 * 
	 * @param name
	 * @return
	 */
	private boolean isValidPropertyName(String name) {
		return !(name.startsWith("$") || "serialVersionUID".equals(name) || "class".equals(name));
	}

	/**
	 * This method returns an array containing all methods declared in this
	 * class and any superclass. We use this method, instead of the simpler
	 * Class.getMethods(), because we want to look for private methods as well.
	 * 得到所有方法，包括private方法，包括父类方法.包括接口方法
	 *
	 * @param cls
	 *            The class
	 * 
	 * @return An array containing all methods in this class
	 */
	private Method[] getClassMethods(Class<?> cls) {
		Map<String, Method> uniqueMethods = new HashMap<String, Method>();
		Class<?> currentClass = cls;
		// 如果当前的class是否不为空
		while (currentClass != null) {
			addUniqueMethods(uniqueMethods, currentClass.getDeclaredMethods());

			// we also need to look for interface methods -
			// because the class may be abstract
			// 确定此对象所表示的类或接口实现的接口
			Class<?>[] interfaces = currentClass.getInterfaces();
			for (Class<?> anInterface : interfaces) {
				addUniqueMethods(uniqueMethods, anInterface.getMethods());
			}

			currentClass = currentClass.getSuperclass();
		}

		Collection<Method> methods = uniqueMethods.values();

		return methods.toArray(new Method[methods.size()]);
	}

	/**
	 * 添加一个独特的方法集
	 * 
	 * @param uniqueMethods
	 * @param methods
	 */
	private void addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods) {
		// 遍历
		for (Method currentMethod : methods) {
			// 如果此方法是 bridge 方法，则返回 true；否则，返回 false
			if (!currentMethod.isBridge()) {
				// 取得签名
				String signature = getSignature(currentMethod);
				// check to see if the method is already known
				// if it is known, then an extended class must have
				// overridden a method
				// 判断uniqueMethods是否不存在signature方法
				if (!uniqueMethods.containsKey(signature)) {
					// 判断是否可以访问私人方法
					if (canAccessPrivateMethods()) {
						try {
							// 为反射对象设置可访问标志，flag为true表明屏蔽Java语言的访问检查，使得对象的私有属性也可以被查询和设置
							currentMethod.setAccessible(true);
						} catch (Exception e) {
							// Ignored. This is only a final precaution, nothing
							// we can do.
						}
					}

					uniqueMethods.put(signature, currentMethod);
				}
			}
		}
	}

	/**
	 * 得到签名
	 * 
	 * @param method
	 * @return
	 */
	private String getSignature(Method method) {
		StringBuilder sb = new StringBuilder();
		// 得到返回的类型
		Class<?> returnType = method.getReturnType();
		// 判断不为空
		if (returnType != null) {
			sb.append(returnType.getName()).append('#');
		}
		sb.append(method.getName());
		// 得到参数的类型
		Class<?>[] parameters = method.getParameterTypes();

		for (int i = 0; i < parameters.length; i++) {
			if (i == 0) {
				sb.append(':');
			} else {
				sb.append(',');
			}
			sb.append(parameters[i].getName());
		}
		return sb.toString();
	}

	/**
	 * 是否可以访问私人方法
	 * 
	 * @return
	 */
	private static boolean canAccessPrivateMethods() {
		try {
			// 得到系统安全接口。
			SecurityManager securityManager = System.getSecurityManager();
			if (null != securityManager) {
				// 如果基于当前有效的安全策略，不允许执行根据给定权限所指定的请求访问
				securityManager.checkPermission(new ReflectPermission("suppressAccessChecks"));
			}
		} catch (SecurityException e) {
			return false;
		}
		return true;
	}

	/**
	 * Gets the name of the class the instance provides information
	 * for(获取实例提供的信息的类的名称)
	 *
	 * @return The class name
	 */
	public Class<?> getType() {
		return type;
	}

	/**
	 * 得到默认的构造器
	 * 
	 * @return
	 */
	public Constructor<?> getDefaultConstructor() {
		if (defaultConstructor != null) {
			return defaultConstructor;
		} else {
			throw new ReflectionException("There is no default constructor for " + type);
		}
	}

	/**
	 * 判断是否有默认的构造器
	 * 
	 * @return
	 */
	public boolean hasDefaultConstructor() {
		return defaultConstructor != null;
	}

	/**
	 * 得到Set代理
	 * 
	 * @param propertyName
	 * @return
	 */
	public Invoker getSetInvoker(String propertyName) {
		Invoker method = setMethods.get(propertyName);
		if (method == null) {
			throw new ReflectionException(
					"There is no setter for property named '" + propertyName + "' in '" + type + "'");
		}
		return method;
	}

	/**
	 * 得到Get代理
	 * 
	 * @param propertyName
	 * @return
	 */
	public Invoker getGetInvoker(String propertyName) {
		Invoker method = getMethods.get(propertyName);
		if (method == null) {
			throw new ReflectionException(
					"There is no getter for property named '" + propertyName + "' in '" + type + "'");
		}
		return method;
	}

	/**
	 * Gets the type for a property setter(获取属性设置器的类型。)
	 *
	 * @param propertyName
	 *            - the name of the property
	 * 
	 * @return The Class of the propery setter
	 */
	public Class<?> getSetterType(String propertyName) {
		Class<?> clazz = setTypes.get(propertyName);
		if (clazz == null) {
			throw new ReflectionException(
					"There is no setter for property named '" + propertyName + "' in '" + type + "'");
		}
		return clazz;
	}

	/**
	 * Gets the type for a property getter(获取属性的getter的类型)
	 *
	 * @param propertyName
	 *            - the name of the property
	 * 
	 * @return The Class of the propery getter
	 */
	public Class<?> getGetterType(String propertyName) {
		Class<?> clazz = getTypes.get(propertyName);
		if (clazz == null) {
			throw new ReflectionException(
					"There is no getter for property named '" + propertyName + "' in '" + type + "'");
		}
		return clazz;
	}

	/**
	 * Gets an array of the readable properties for an object(获取对象可读属性的数组。)
	 *
	 * @return The array
	 */
	public String[] getGetablePropertyNames() {
		return readablePropertyNames;
	}

	/**
	 * Gets an array of the writeable properties for an object(获取一个对象的可写属性的数组)
	 *
	 * @return The array
	 */
	public String[] getSetablePropertyNames() {
		return writeablePropertyNames;
	}

	/**
	 * Check to see if a class has a writeable property by name(检察名字类有一个可写的属性)
	 *
	 * @param propertyName
	 *            - the name of the property to check
	 * 
	 * @return True if the object has a writeable property by the name
	 */
	public boolean hasSetter(String propertyName) {
		return setMethods.keySet().contains(propertyName);
	}

	/**
	 * Check to see if a class has a readable property by name(检查某个类是否有可读属性的名称。)
	 *
	 * @param propertyName - the name of the property to check
	 * 
	 * @return True if the object has a readable property by the name
	 */
	public boolean hasGetter(String propertyName) {
		return getMethods.keySet().contains(propertyName);
	}
	/**
	 * 查找property的名字
	 * @param name
	 * @return
	 */
	public String findPropertyName(String name) {
		return caseInsensitivePropertyMap.get(name.toUpperCase(Locale.ENGLISH));
	}

	/**
	 * Gets an instance of ClassInfo for the specified class.
	 * 得到某个类的反射器，是静态方法，而且要缓存，又要多线程，所以REFLECTOR_MAP是一个ConcurrentHashMap
	 *
	 * @param clazz The class for which to lookup the method cache.
	 * 
	 * @return The method cache for the class
	 */
	public static Reflector forClass(Class<?> clazz) {
		if (classCacheEnabled) {
			// synchronized (clazz) removed see issue #461
			// 对于每个类来说，我们假设它是不会变的，这样可以考虑将这个类的信息(构造函数，getter,setter,字段)加入缓存，以提高速度
			Reflector cached = REFLECTOR_MAP.get(clazz);
			if (cached == null) {
				cached = new Reflector(clazz);
				REFLECTOR_MAP.put(clazz, cached);
			}
			return cached;
		} else {
			return new Reflector(clazz);
		}
	}
	/**
	 * 设置是否开启类缓存
	 * @param classCacheEnabled
	 */
	public static void setClassCacheEnabled(boolean classCacheEnabled) {
		Reflector.classCacheEnabled = classCacheEnabled;
	}
	/**
	 * 是否开启类缓存
	 * @return
	 */
	public static boolean isClassCacheEnabled() {
		return classCacheEnabled;
	}
}